from logging import raiseExceptions

from bcat.util.str import Str

from bcat.gtp.serde.de.deserializer import Deserializer

from bcat.gtp.serde.error import ExpectTypeError, ValueEmptyError

from bcat.gtp.serde.error import NeedCommaError, NewValueError


class Validator(object):
    def __init__(self, encoding="gbk"):
        self.__encoding = encoding

    def validate_str(self, s):
        if type(s) is not str:
            raise ExpectTypeError(str, type(s))
        return self.validate(Str(s).to_bytes(self.__encoding))

    def validate(self, in_bytes):
        if type(in_bytes) is not bytes:
            raise ExpectTypeError(bytes, type(in_bytes))

        if len(in_bytes) == 0:
            raise ValueEmptyError("in_bytes len == 0")
        
        deserializer = Deserializer(in_bytes)

        while True:
            self.__validate_pair(deserializer)
            
            if not deserializer.is_end():
                if not deserializer.deser_pair_sep():
                    # not pair separator after deser_pair
                    raise NeedCommaError(deserializer.position())

            else:
                # end
                break
        return True

    def __validate_pair(self, deserializer):
        self.__validate_key(deserializer)

        if not deserializer.is_end():
            deserializer.deser_key_value_sep()
        else:
            # not kv separator after deser_key
            raise NeedCommaError(deserializer.position())

        self.__validate_value(deserializer)


    def __validate_key(self, deserializer):
        deserializer.deser_key()

    def __validate_value(self, deserializer):
        self.__validate_string(deserializer)# todo


    def __validate_string(self, deserializer):
        deserializer.deser_string()

    def __validate_objetct(self, deserializer):
        print("validate object")




import unittest
class TestValidator(unittest.TestCase):
    def test_main(self):
        gtp_in = "X01=123,X02=abc"

        pa = Validator()
        result = pa.validate_str(gtp_in)
        self.assertTrue(result)


        #for i in range(10):
        #    result = pa.validate(Str(gtp_in).to_bytes())

        #TODO: result = pa.validate(gtp_in) #expect raise exception
        #TODO: raise Exception pa.validate(bytes())

    def test_invaild_gtp(self):
        gtp_in = "X01=123,"

        pa = Validator()
        try:
            ret = pa.validate_str(gtp_in)
        except ValueError as e:
            print(str(e))

        self.assertRaises(NewValueError,pa.validate_str, gtp_in)


if __name__ == '__main__':
    unittest.main(verbosity=2)
